<?php
namespace app\admin\logic;

use app\admin\model\Admin;
use app\admin\model\AdminRole;
use app\admin\model\MenuNode;
use app\admin\model\RoleNode;
use app\common\service\auth\JwtService;
use app\common\traits\RemoteTrait;
use think\Exception;
use think\facade\Filesystem;
use think\facade\Request;


/**
 * 后台管理人员
 * Class AdminLogic
 * @package app\admin\logic
 * @author ^2_3^王尔贝
 */
class AdminLogic
{
    use RemoteTrait;

    private $adminModel;

    private $adminRoleModel;

    private $menuNodeModel;

    private $roleNodeModel;

    private $jwtService;

    public function __construct()
    {
        $this->adminModel = new Admin();
        $this->adminRoleModel = new AdminRole();
        $this->menuNodeModel = new MenuNode();
        $this->roleNodeModel = new RoleNode();
        $this->jwtService = JwtService::getInstance();
    }

    /**
     * 个人设置
     * @param array $params
     * @return bool|\think\Collection
     * @author ^2_3^王尔贝
     */
    public function basicSetting($params = [])
    {
        $flag = false;
        if (empty($params)) {
            return $flag;
        }

        $data = [
            'id' => $params['id'],
            'nickname' => $params['nickname'],
            'profile' => $params['profile'],
            'email' => $params['email'],
            'avatar' => $params['avatar'],
        ];
        $flag = $this->adminModel->_saveAll([$data]);

        return $flag;
    }

    /**
     * 处理头像
     * @param $avatar
     * @param array $adminInfo
     * @return bool|string
     * @author ^2_3^王尔贝
     */
    public function handleAvatar($avatar, $adminInfo = [])
    {
        try {
            $rand = rand(100000, 999999);
            $name = "{$adminInfo['username']}_{$rand}.jpg";
            $avatarUrl = Filesystem::disk('public')->putFileAs('avatar', $avatar, $name);

            if ($avatarUrl) {
                //// 更新头像
                $host = Request::host();
                stripos($host, 'http') === false && $host = "http://{$host}";
                $avatarUrl = "{$host}/storage/{$avatarUrl}";
                //
                $data = [
                    'id' => $adminInfo['id'],
                    'avatar' => $avatarUrl,
                ];
                $flag = $this->adminModel->_saveAll([$data]);
                //
                if( $flag === false ) {
                    delFile($avatarUrl);
                    return false;

                }else {
                    $adminAvatar = $adminInfo['avatar'];
                    delFile($adminAvatar);

                    return $avatarUrl;
                }
            }

        }catch (Exception $e) {
            return false;
        }
    }

    /**
     * 生成树形结构
     * @param array $list
     * @param int $pid
     * @return array
     * @author ^2_3^王尔贝
     */
    private function generateTree($list = [], $pid = 0)
    {
        $result = [];
        if( empty( $list ) ) {
            return $result;
        }

        foreach ( $list as $key=>$item ) {
            $item = $item->toArray();
            if( $item['pid'] == $pid ) {
                //// 扩展数据
                if( !empty( $item['param'] ) ) {
                    $extendArr = json_decode( $item['param'],true);
                    unset( $item['param'] );

                    $item = array_merge($item, $extendArr);
                }

                $childResult = $this->generateTree($list, $item['id']);
                if( !empty( $childResult ) ) {
                    $item['children'] = $childResult;
                }

                $result[] = $item;
            }
        }

        return $result;
    }

    /**
     * 按树形排序列表
     * @param array $list
     * @param int $pid
     * @return array
     * @author ^2_3^王尔贝
     */
    private function generateSort($list = [], $pid = 0)
    {
        $result = [];
        if( empty( $list ) ) {
            return $result;
        }

        foreach ( $list as $key=>$item ) {
            $item = $item->toArray();
            if( $item['pid'] == $pid ) {
                //// 扩展数据
                if( !empty( $item['param'] ) ) {
                    $extendArr = json_decode( $item['param'],true);
                    unset( $item['param'] );

                    $item = array_merge($item, $extendArr);
                }

                $result[] = $item;

                $childResult = $this->generateSort($list, $item['id']);
                if( !empty( $childResult ) ) {
                    $result = array_merge($result, $childResult);
                }

            }
        }

        return $result;
    }

    /**
     * 缩短树形
     * @param array $treeList
     * @return array
     * @author ^2_3^王尔贝
     */
    private function cutDownTree($treeList = [])
    {
        $result = [];

        foreach ($treeList as $item) {
            $title = '';

            if ($item['is_menu'] == 1 && !empty($item['children'])) {
                $title = empty($title) ? $item['title'] : "{$title}/{$item['title']}";
                $tmp = $this->cutDownTreeHandle($item['children'], $title);
                !empty($tmp) && $result = array_merge($result, $tmp);
            }
        }

        return $result;
    }
    private function cutDownTreeHandle($treeArr = [], $title = '')
    {
        $result = [];

        foreach ($treeArr as $item) {
            if ($item['is_menu'] == 1 && !empty($item['children'])) {
                $title = empty($title) ? $item['title'] : "{$title}/{$item['title']}";
                $tmp = $this->cutDownTreeHandle($item['children'], $title);
                $result[] = [
                    'title' => $title,
                    'actions' => $tmp,
                ];
                $titleArr = explode('/', $title);
                unset($titleArr[count($titleArr)-1]);
                $title = implode('/', $titleArr);

            }else if ($item['is_menu'] == 0) {
                $result[] = $item;
            }
        }

        return $result;
    }

    /**
     * 密码强度
     * @param int $strength
     * @return string
     * @author ^2_3^王尔贝
     */
    private function getStrength($strength = 0)
    {
        switch ($strength) {
            case 0:
                $strengthText = '(请增强～)';
                break;
            case 1:
                $strengthText = '弱';
                break;
            case 2:
                $strengthText = '中';
                break;
            case 3:
                $strengthText = '强';
                break;
            default:
                $strengthText = '(未能侦测~)';
        }

        return $strengthText;
    }

    /**
     * 管理人员信息
     * @param array $params
     * @return array
     * @author ^2_3^王尔贝
     */
    public function info($params = [])
    {
        /* // 目标
        $info = [
            "name" => '',
            "avatar" => '',
            "role" => [ //角色(单个多个)权限
                "permissions" => [
                    [
                        // 权限节点(菜单节点/操作节点)
                    ]
                ]
            ]
        ];
        */

        $oriInfo = $params['info'];
        $info = [
            'id' => $oriInfo['id'],
            'nickname' => $oriInfo['nickname'],
            'username' => $oriInfo['username'],
            'name' => $oriInfo['username'],
            'avatar' => empty($oriInfo['avatar']) ? '/avatar2.jpg' : $oriInfo['avatar'],
            'email' => $oriInfo['email'],
            'profile' => $oriInfo['profile'],
            'status' => $oriInfo['status'],
            'strength' => $this->getStrength($oriInfo['strength']),
            'role' => [],
        ];

        $roleIds = $params['roleIds'];
        $nodeWhere = [];
        if( !in_array(1, $roleIds) ) {
            $rnWhere = [
                ['role_id', 'in', $roleIds],
            ];
            $nodeIds = $this->roleNodeModel->_column($rnWhere, 'node_id');
            !empty($nodeIds) && $nodeIds = array_unique($nodeIds);
            $nodeWhere[] = ['id', 'in', $nodeIds];
        }
        $nodeList = $this->menuNodeModel->listOnly($nodeWhere);

        $permissions = $this->generateSort($nodeList);
        $info['role']['permissions'] = $permissions;

        $permissionsTree = $this->generateTree($nodeList);
        $info['role']['permissions_tree'] = $permissionsTree;

        $info['role']['permissions_action'] = $this->cutDownTree($permissionsTree);

//        $info = [
//            "id" => '4291d7da9005377ec9aec4a71ea837f',
//            "name" => '天野远子',
//            "username" => 'admin',
//            "password" => '',
//            "avatar" => '/avatar2.jpg',
//            "status" => 1,
//            "telephone" => '',
//            "lastLoginIp" => '27.154.74.117',
//            "lastLoginTime" => 1534837621348,
//            "creatorId" => 'admin',
//            "createTime" => 1497160610259,
//            "merchantCode" => 'TLif2btpzg079h15bk',
//            "deleted" => 0,
//            "roleId" => 'admin',
//            "role" => [
//                //// 管理员角色
//                "id" => 'admin',
//                "name" => '管理员',
//                "describe" => '拥有所有权限',
//                "status" => 1,
//                "creatorId" => 'system',
//                "createTime" => 1497160610259,
//                "deleted" => 0,
//                "permissions" => [
//                    [
//                        //// 仪表盘权限
//                        "roleId" => 'admin',
//                        "permissionId" => 'dashboard',
//                        "permissionName" => '仪表盘',
//                        "actions" => '[{"action":"add","defaultCheck":false,"describe":"新增"},{"action":"query","defaultCheck":false,"describe":"查询"},{"action":"get","defaultCheck":false,"describe":"详情"},{"action":"update","defaultCheck":false,"describe":"修改"},{"action":"delete","defaultCheck":false,"describe":"删除"}]',
//                        "actionEntitySet" => [
//                            [
//                                "action" => 'add',
//                                "describe" => '新增',
//                                "defaultCheck" => false
//                            ],
//                            [
//                                "action " => 'query',
//                                "describe" => '查询',
//                                "defaultCheck" => false
//                            ],
//                            [
//                                "action" => 'get',
//                                "describe" => '详情',
//                                "defaultCheck" => false
//                            ],
//                            [
//                                "action" => 'update',
//                                "describe" => '修改',
//                                "defaultCheck" => false
//                            ],
//                            [
//                                "action" => 'delete',
//                                "describe" => '删除',
//                                "defaultCheck" => false
//                            ]
//                        ],
//                        "actionList" => null,
//                        "dataAccess" => null
//                    ]
//                ]
//            ]
//        ];
        return $info;
    }

    /**
     * 分页列表
     * @param array $params
     * @return mixed
     * @author ^2_3^王尔贝
     */
    public function listPage($params = [])
    {
        $where = [];
        if( !empty( $params['id'] ) ) {
            $where['id'] = $params['id'];
        }
        if( !empty( $params['username'] ) ) {
            $where[] = ['username', 'like', "%{$params['username']}%"];
        }
        if( !empty( $params['status'] ) && $params['status'] == 1 ) {
            $where['status'] = 1; // 正常；

        }else if( !empty( $params['status'] ) && $params['status'] == 2 ) {
            $where['status'] = 0; // 禁用；
        }
        $orderBy = '';
        if( !empty( $params['sortField'] ) ) {
            $sortField = $params['sortField'];
            $sortOrder = $params['sortOrder'] ?? 'desc';
            $orderBy = "{$sortField} {$sortOrder}";

        }else {
            $orderBy = "id desc";
        }

        $field = 'id, id as `key`, username, status, user_id, login_times, last_login_time, last_login_ip, created_at, updated_at';
        $page = $params['pageNo'] ?? 1;
        $pageSize = $params['pageSize'] ?? 10;
        $listPage = $this->adminModel->listPage($where, $field, $page, $orderBy, $pageSize);
        $adminIds = [];
        if( !$listPage->isEmpty() ) {
            $adminIds = array_column($listPage->items(), 'id');
        }

        //// admin role
        $arList = $this->adminRoleModel->listOnly();
        $arArr = [];
        foreach ( $arList as $ar ) {
            $arArr[ $ar['admin_id'] ][] = $ar['role_id'];
        }

        foreach ($listPage->items() as $item) {
            if( isset( $arArr[$item['id']] ) ) {
                $item['roles'] = $arArr[$item['id']];
            }
        }

        return $listPage;
    }

    /**
     * login
     * @param array $params
     * @return array|bool
     * @author ^2_3^王尔贝
     */
    public function login($params = [])
    {
        $flag = false;
        if( empty( $params ) || empty( $params['username'] ) || empty( $params['password'] ) ) {
            return $flag;
        }

        //// info
        $where = [
            'username' => $params['username'],
            'status' => 1,
        ];
        $admin = $this->adminModel->_find( $where );
        if( empty( $admin ) ) {
            return $flag;
        }

        //// password
        $admin = $admin->toArray();
        $password = md5( $params['password'].'?43?23?11?'.md5('?'.$admin['salt']) );
        if( $password != $admin['password'] ) {
            return $flag;
        }

        //// update
        $nowTime = time();
        $data = [
            'id' => $admin['id'],
            'login_times' => $admin['login_times'] + 1,
            'last_login_time' => $nowTime,
            'last_login_ip' => $this->getRealIP(),
        ];
        $uFlag = $this->adminModel->_saveAll( [ $data ] );

        //// session验证方式
        // session('ADMIN_ID', $admin['id']);

        //// jwt验证方式
        $jwtObject = $this->jwtService->makeToken( $admin['id'] );
        $admin['token'] = $jwtObject->token;

        $flag = $admin;
        return $flag;
    }

    /**
     * 修改密码
     * @param array $params
     * @return bool|mixed|\think\Collection
     * @author ^2_3^王尔贝
     */
    public function changePass($params = [])
    {
        $flag = false;
        if (empty($params)) {
            return $flag;
        }

        //// password no match
        $passOri = getPassword($params['ori_pass'], $params['salt']);
        $password = getPassword($params['pass'], $params['salt']);
        if ($passOri !== $params['password']) {
            return $flag;
        }

        $data = [
            'id' => $params['id'],
            'password' => $password,
            'strength' => $params['strength'], //1-数字; 2-数字字母; 3-数字字母符号;
        ];

        $flag = $this->adminModel->_saveAll([$data]);
        if ($flag !== false) {
            $flag = $flag[0];
            $flag['strength'] = $this->getStrength($flag['strength']);
        }

        return $flag;
    }

    /**
     * 保存
     * @param array $params
     * @return bool|\think\Collection
     * @author ^2_3^王尔贝
     */
    public function save($params = [])
    {
        $flag = false;
        if( empty( $params ) || empty( $params['id'] ) ) {
            return $flag;
        }

        $this->adminModel->startTrans();
        try {
            $data = [];
            $data['id'] = $params['id'];

            //// admin info
            $info = $this->adminModel->_find(['id' => $data['id']]);
            $data['username'] = $params['username'] ?? '';
            if( !empty( $params['password'] ) ) {
                $data['password'] = md5( $params['password'].'?43?23?11?'.md5('?'.$info['salt']) );
            }
            $data['status'] = $params['status'] ?? 0;
            $aFlag = $this->adminModel->_saveAll( [$data] );

            //// admin role
            $arWhere = [
                'admin_id' => $params['id'],
            ];
            $roleIds = $this->adminRoleModel->_column($arWhere, 'role_id');
            //
            $arFlag = false;
            $roleAdd = [];
            $roleDel = [];
            if(empty($params['roles']) && empty($roleIds)) {
                $arFlag = true;

            }else if( !empty($params['roles']) && empty($roleIds) ) {
                $roleAdd = $params['roles'];

            }else if( empty($params['roles']) && !empty($roleIds) ) {
                $roleDel = $roleIds;

            }else {
                $roleAdd = array_diff($params['roles'], $roleIds);
                $roleDel = array_diff($roleIds, $params['roles']);
            }

            if( !empty($roleAdd) ) {
                $addData = [];
                foreach ($roleAdd as $roleId) {
                    $addData[] = [
                        'admin_id' => $params['id'],
                        'role_id' => $roleId,
                        'create_time' => time(),
                    ];
                }
                $arFlag = $this->adminRoleModel->_saveAll( $addData );
            }

            if( !empty($roleDel) ) {
                $delWhere = [
                    ['admin_id', '=', $params['id']],
                    ['role_id', 'in', $roleDel],
                ];
                $arFlag = $this->adminRoleModel->_delete($delWhere);
            }

            if( $aFlag !== false && $arFlag !== false ) {
                $this->adminModel->commit();
                $flag = true;
                lo('commit');

            }else {
                $this->adminModel->rollback();
                $flag = false;
                lo('rollback');
            }

        }catch (Exception $e) {
            $this->adminModel->rollback();
            $flag = false;
            lo('Exception rollback');
        }

        return $flag;
    }

    /**
     * 注册
     * @param array $params
     * @return bool|\think\Collection
     * @author ^2_3^王尔贝
     */
    public function register($params = [])
    {
        $flag = false;

        $this->adminModel->startTrans();
        $arFlag = false;

        try {
            $salt = random_int(1000, 9999);
            $nowTime = time();
            $data = [
                'username' => $params['username'],
                'password' => md5( $params['password'].'?43?23?11?'.md5('?'.$salt) ),
                'salt' => $salt,
                'status' => $params['status'] ?? 1,
                'login_times' => 1,
                'last_login_time' => $nowTime,
                'last_login_ip' => $this->getRealIP(),
            ];
            $aFlag = $this->adminModel->_saveAll( [$data] );

            if( empty( $params['roles'] ) ) {
                $arFlag = true;

            }else {
                $adminId = $aFlag[0]['id'];
                $roleArr = $params['roles'];
                $roleDate = [];
                foreach ( $roleArr as $roleId ) {
                    $roleDate[] = [
                        'admin_id' => $adminId,
                        'role_id' => $roleId,
                        'create_time' => time(),
                    ];
                }
                $arFlag = $this->adminRoleModel->_saveAll( $roleDate );
            }

            if( $aFlag !== false && $arFlag !== false ) {
                $this->adminModel->commit();
                $flag = true;

            }else {
                $this->adminModel->rollback();
                $flag = false;
            }
            return $flag;

        }catch (Exception $e) {
            $this->adminModel->rollback();
            $flag = false;
            return $flag;
        }
    }
}